#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace KLib.Graphics
{
    public class SpriteRenderer : Microsoft.Xna.Framework.Graphics.SpriteBatch
    {

        #region Static
        private static SpriteFont defaultFont;
        #endregion

        #region Fields

        Microsoft.Xna.Framework.Content.ContentManager content;
        bool useCamera = true;

        [OptionalService]
        public Camera.ICamera camera;
        #endregion

        #region Properties
        /// <summary>
        /// Gets or Sets if the SpriteRenderer automatically Uses a Camera (render positions are effected by the camera)
        /// </summary>
        public bool UseCamera
        {
            get { return useCamera && camera != null; }
            set { useCamera = value; }
        }
        #endregion

        #region Initialization
        public SpriteRenderer(GraphicsDevice graphicsDevice)
            :base(graphicsDevice)
        {

        }
        public SpriteRenderer(GraphicsDevice graphicsDevice, Game game)
            : base(graphicsDevice)
        {
            content = new Microsoft.Xna.Framework.Content.ContentManager(game.Services, "Content");
            if (SpriteRenderer.defaultFont == null)
                defaultFont = content.Load<SpriteFont>("Fonts/Default");

                Reflection.Reflect(game, this);
        }
        #endregion

        #region Methods

        #region Begin Overrides
        /// <summary>
        /// Begins the SpriteRenderer with default values of
        /// SpriteBlendMode.Alpha Blend,
        /// SpriteSortMode.Immediate,
        /// SaveStateMode.None
        /// </summary>
        public new void Begin()
        {
            if (UseCamera)
                base.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None,camera.GetCameraMatrix());
            else
            base.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);
        }

        public void Begin(Matrix cameraMatrix)
        {
            base.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None, cameraMatrix);
        }
        /// <summary>
        /// Begins the SpriteRenderer with default values of
        /// SpriteBlendMode.Alpha Blend,
        /// SpriteSortMode.Immediate,
        /// </summary>
        public void Begin(SaveStateMode mode)
        {
            base.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, mode);
        }
        #endregion

        #region Draw Overrides
        public void Draw(Texture2D texture, Vector2 position)
        {
            if (texture == null || texture.IsDisposed)
                return;
                base.Draw(texture,
                    position,
                    new Rectangle(0, 0, texture.Width, texture.Height),
                    Color.White,
                    0f,
                    Vector2.Zero,
                    Vector2.One,
                    SpriteEffects.None, 0);
        }
        public void Draw(Sprite sprite)
        {
            if (sprite.Texture == null || sprite.Texture.IsDisposed)
                return;
                base.Draw(sprite.Texture,
                    sprite.Position,
                    new Rectangle(0, 0, (int)sprite.Size.X, (int)sprite.Size.Y),
                    Color.White,
                    sprite.Rotation,
                    Vector2.Zero,
                    Vector2.One,
                    SpriteEffects.None, 0);
        }

        public void Draw(Entities.Entity entity)
        {
            if (entity.Texture == null || entity.Texture.IsDisposed)
                return;
            base.Draw(entity.Texture,
                entity.Position,
                new Rectangle(0, 0, entity.Texture.Width, entity.Texture.Height),
                entity.Color,
                entity.Rotation,
                new Vector2(entity.Texture.Width / 2, entity.Texture.Height / 2),
                Vector2.One,
                SpriteEffects.None, 0);
        }

        public void Draw(Entities.Entity entity, Color color)
        {
            if (entity.Texture == null || entity.Texture.IsDisposed)
                return;

            base.Draw(entity.Texture,
                entity.Position,
                new Rectangle(0, 0, entity.Texture.Width, entity.Texture.Height),
                color,
                entity.Rotation,
                new Vector2(entity.Texture.Width / 2, entity.Texture.Height / 2),
                Vector2.One,
                SpriteEffects.None, 0);
        }
        #endregion

        #region DrawString Overrides

        /// <summary>
        /// Draws a string with a default font (Arial 14) at the specified position
        /// </summary>
        public void DrawString(string text, Vector2 position)
        {
            if (!string.IsNullOrEmpty(text))
            base.DrawString(defaultFont, text, position, Color.White);
        }


        /// <summary>
        /// Draws a String that fits inside a region (text is wrapped down to the next line)
        /// </summary>
        /// <returns>True if all the text fit</returns>
        public bool DrawWrappedString(string text, Rectangle region)
        {
            return DrawWrappedString(SpriteRenderer.defaultFont, text, region, Color.White);
        }

        /// <summary>
        /// Draws a String that fits inside a region (text is wrapped down to the next line)
        /// </summary>
        /// <returns>True if all the text fit</returns>
        public bool DrawWrappedString(SpriteFont font, string text, Rectangle region)
        {
            return DrawWrappedString(font, text, region, Color.White);
        }

        /// <summary>
        /// Draws a String that fits inside a region (text is wrapped down to the next line)
        /// </summary>
        /// <returns>True if all the text fit</returns>
        public bool DrawWrappedString(string text, Rectangle region, Color color)
        {
            return DrawWrappedString(SpriteRenderer.defaultFont, text, region, color);
        }

        /// <summary>
        /// Draws a String that fits inside a region (text is wrapped down to the next line)
        /// </summary>
        /// <returns>True if all the text fit</returns>
        public bool DrawWrappedString(SpriteFont font, string text, Rectangle region, Color color)
        {
            bool entireStringFit = true;
            string[] words = text.Split(' ');
            StringBuilder builder = new StringBuilder();

            float lineWidth = 0.0f;
            float lineHeight = font.LineSpacing;
            float spaceWidth = font.MeasureString(" ").X;
            int lineCount = 1;

            for (int i = 0; i < words.Length; i++)
            {
                Vector2 size = defaultFont.MeasureString(words[i]);

                if (lineWidth + size.X < region.Width)
                {
                    builder.Append(words[i] + " ");
                    lineWidth += size.X + spaceWidth;
                }
                else if (lineHeight * (lineCount + 1) < region.Height)
                {
                    builder.Append("\n" + words[i] + " ");
                    lineWidth = size.X + spaceWidth;
                    lineCount++;
                }
                else
                {
                    entireStringFit = false;
                }
            }
            base.DrawString(defaultFont, builder.ToString(), new Vector2(region.X, region.Y), color);
            return entireStringFit;
        }
        #endregion

        #endregion

        #region Helper Methods

        #endregion
    }
}
